Popular Searches
Popular Course Categories
Popular Courses

LayoutBuilder in Flutter

LayoutBuilder in Flutter

Flutter Responsive Design


LayoutBuilder in Flutter


LayoutBuilder is an important Flutter widget used to create responsive and adaptive user interfaces. It allows a widget to understand the layout constraints provided by its parent and build its UI accordingly.


Unlike MediaQuery, which provides information about the overall application window, LayoutBuilder provides the constraints available at the specific location where it is placed in the widget tree. Flutter's official documentation describes this as a useful approach when a custom widget needs to adapt to the space specifically given to that widget. Flutter Adaptive Layout Documentation


1. What is LayoutBuilder?


LayoutBuilder is a widget that provides a BoxConstraints object to its builder callback. These constraints describe the minimum and maximum width and height available to the widget.


Basic syntax:


LayoutBuilder(
  builder: (BuildContext context, BoxConstraints constraints) {
    return YourWidget();
  },
)

The constraints object allows you to access:



  • constraints.minWidth

  • constraints.maxWidth

  • constraints.minHeight

  • constraints.maxHeight


Flutter's layout model follows the basic rule: constraints go down, sizes go up, and the parent sets the position. Flutter Understanding Constraints


2. Why Use LayoutBuilder?


LayoutBuilder is useful when a widget needs to change its layout according to the amount of space actually provided by its parent.


For example, suppose a card is displayed inside a narrow container on one page and inside a wide container on another page. Using the overall screen size may not accurately represent the space available to the card.


LayoutBuilder solves this problem by providing the local constraints of the widget.



  • Create responsive components.

  • Change layouts according to available width.

  • Build reusable responsive widgets.

  • Choose different column counts.

  • Switch between Row and Column layouts.

  • Create responsive cards.

  • Build adaptive dashboards.

  • Create responsive navigation sections.

  • Handle widgets placed inside different parent containers.


3. Basic LayoutBuilder Syntax


LayoutBuilder(
  builder: (context, constraints) {
    return Container(
      width: constraints.maxWidth,
      height: constraints.maxHeight,
      color: Colors.blue,
    );
  },
)

The builder receives two parameters:






ParameterPurpose
contextProvides information about the widget's location in the widget tree.
constraintsProvides the minimum and maximum size available from the parent.

4. Understanding BoxConstraints


LayoutBuilder gives you a BoxConstraints object.


LayoutBuilder(
  builder: (context, constraints) {
    print(constraints.minWidth);
    print(constraints.maxWidth);
    print(constraints.minHeight);
    print(constraints.maxHeight);

    return const SizedBox();
  },
)


A BoxConstraints contains four important values:








PropertyMeaning
minWidthSmallest width the widget can use.
maxWidthLargest width the widget can use.
minHeightSmallest height the widget can use.
maxHeightLargest height the widget can use.

Flutter's official constraints documentation explains that a widget receives constraints from its parent and must choose a size within those constraints. Flutter Constraints Documentation


5. Simple LayoutBuilder Example


import 'package:flutter/material.dart';

class SimpleLayoutBuilder extends StatelessWidget {
  const SimpleLayoutBuilder({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: LayoutBuilder(
        builder: (context, constraints) {
          return Center(
            child: Text(
              "Available Width: ${constraints.maxWidth}",
              style: const TextStyle(fontSize: 20),
            ),
          );
        },
      ),
    );
  }
}


6. Detecting Available Width


The most common use of LayoutBuilder is checking constraints.maxWidth.


LayoutBuilder(
  builder: (context, constraints) {
    final width = constraints.maxWidth;

    return Text(
      "Available width: $width",
    );
  },
)


This value represents the maximum width available to the LayoutBuilder from its parent.


7. Detecting Available Height


You can also access the maximum available height:


LayoutBuilder(
  builder: (context, constraints) {
    final height = constraints.maxHeight;

    return Text(
      "Available height: $height",
    );
  },
)


8. Creating Responsive Layouts


LayoutBuilder can be used to create different layouts according to available width.


LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth < 600) {
      return const MobileLayout();
    }

    return const DesktopLayout();
  },
)


The breakpoint should be selected according to the layout requirements. Flutter's adaptive-layout examples commonly use 600 logical pixels as an example breakpoint, but it is not a universal rule for every application. Flutter LayoutBuilder and Adaptive Layouts


9. Mobile and Tablet Layout Example


class ResponsiveContent extends StatelessWidget {
  const ResponsiveContent({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth < 600) {
          return const Column(
            children: [
              Text("Mobile Layout"),
              Text("Content displayed vertically"),
            ],
          );
        }

        return const Row(
          children: [
            Expanded(
              child: Text("Tablet/Desktop Item 1"),
            ),
            Expanded(
              child: Text("Tablet/Desktop Item 2"),
            ),
          ],
        );
      },
    );
  }
}


10. LayoutBuilder with Row


You can use LayoutBuilder to decide how many widgets should appear horizontally.


LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth < 600) {
      return const Row(
        children: [
          Expanded(child: Text("Item 1")),
          Expanded(child: Text("Item 2")),
        ],
      );
    }

    return const Row(
      children: [
        Expanded(child: Text("Item 1")),
        Expanded(child: Text("Item 2")),
        Expanded(child: Text("Item 3")),
        Expanded(child: Text("Item 4")),
      ],
    );
  },
)


11. LayoutBuilder with Column


For narrow layouts, content can be displayed vertically.


LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth < 500) {
      return const Column(
        children: [
          Text("Product Image"),
          Text("Product Name"),
          Text("Product Price"),
        ],
      );
    }

    return const Row(
      children: [
        Expanded(child: Text("Product Image")),
        Expanded(
          child: Column(
            children: [
              Text("Product Name"),
              Text("Product Price"),
            ],
          ),
        ),
      ],
    );
  },
)


12. LayoutBuilder for Responsive Cards


A reusable card can change its internal design based on its available width.


class ResponsiveCard extends StatelessWidget {
  const ResponsiveCard({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth < 300) {
          return Card(
            child: Padding(
              padding: const EdgeInsets.all(12),
              child: Column(
                children: const [
                  Icon(Icons.person, size: 40),
                  SizedBox(height: 8),
                  Text("Small Card"),
                ],
              ),
            ),
          );
        }

        return Card(
          child: Padding(
            padding: const EdgeInsets.all(20),
            child: Row(
              children: const [
                Icon(Icons.person, size: 60),
                SizedBox(width: 20),
                Text("Wide Card"),
              ],
            ),
          ),
        );
      },
    );
  }
}


13. LayoutBuilder for Grid Columns


LayoutBuilder is very useful when the number of grid columns should depend on the available width.


LayoutBuilder(
  builder: (context, constraints) {
    int columns;

    if (constraints.maxWidth < 500) {
      columns = 2;
    } else if (constraints.maxWidth < 800) {
      columns = 3;
    } else {
      columns = 4;
    }

    return GridView.builder(
      gridDelegate:
          SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: columns,
        crossAxisSpacing: 12,
        mainAxisSpacing: 12,
      ),
      itemCount: 20,
      itemBuilder: (context, index) {
        return Card(
          child: Center(
            child: Text("Item ${index + 1}"),
          ),
        );
      },
    );
  },
)


14. LayoutBuilder with Dashboard Cards


class ResponsiveDashboard extends StatelessWidget {
  const ResponsiveDashboard({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        int columns;

        if (constraints.maxWidth < 600) {
          columns = 1;
        } else if (constraints.maxWidth < 1000) {
          columns = 2;
        } else {
          columns = 4;
        }

        return GridView.count(
          padding: const EdgeInsets.all(16),
          crossAxisCount: columns,
          crossAxisSpacing: 16,
          mainAxisSpacing: 16,
          children: const [
            DashboardCard(
              title: "Users",
              value: "1,250",
            ),
            DashboardCard(
              title: "Orders",
              value: "540",
            ),
            DashboardCard(
              title: "Revenue",
              value: "₹85,000",
            ),
            DashboardCard(
              title: "Pending",
              value: "32",
            ),
          ],
        );
      },
    );
  }
}

class DashboardCard extends StatelessWidget {
  final String title;
  final String value;

  const DashboardCard({
    super.key,
    required this.title,
    required this.value,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(title),
            const SizedBox(height: 8),
            Text(
              value,
              style: const TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
              ),
            ),
          ],
        ),
      ),
    );
  }
}


15. LayoutBuilder vs MediaQuery


One of the most important concepts is understanding when to use LayoutBuilder and when to use MediaQuery.









LayoutBuilderMediaQuery
Provides constraints from the parent widget.Provides information about the application window.
Useful for local component layouts.Useful for overall application-window decisions.
Returns BoxConstraints.Returns size and other media information.
Uses constraints.maxWidth.Uses MediaQuery.sizeOf(context).width.
Can adapt to the space given to a particular widget.Can adapt to the overall window size.

Flutter's official adaptive documentation specifically distinguishes these two approaches: use MediaQuery.sizeOf for the whole app window and LayoutBuilder when you need more local sizing information. Flutter Adaptive Apps Guide


16. Practical Difference Between MediaQuery and LayoutBuilder


Imagine an application window is 1200 pixels wide, but your widget is inside a container that is only 400 pixels wide.


MediaQuery.sizeOf(context).width might report approximately 1200 pixels, while LayoutBuilder can provide constraints that reflect the 400-pixel area available to that particular widget.


Container(
  width: 400,
  child: LayoutBuilder(
    builder: (context, constraints) {
      return Text(
        "Local width: ${constraints.maxWidth}",
      );
    },
  ),
)

This local constraint-based behavior is one of the main reasons LayoutBuilder is useful for reusable responsive components.


17. LayoutBuilder Inside a Container


Container(
  width: 500,
  height: 300,
  padding: const EdgeInsets.all(20),
  child: LayoutBuilder(
    builder: (context, constraints) {
      return Container(
        width: constraints.maxWidth,
        height: constraints.maxHeight,
        color: Colors.blue,
        child: const Center(
          child: Text(
            "Responsive Container",
            style: TextStyle(color: Colors.white),
          ),
        ),
      );
    },
  ),
)

18. LayoutBuilder and Constraints


Suppose a parent provides these constraints:


minWidth = 0
maxWidth = 600
minHeight = 0
maxHeight = 400

LayoutBuilder can access them:


LayoutBuilder(
  builder: (context, constraints) {
    print(constraints.minWidth);
    print(constraints.maxWidth);
    print(constraints.minHeight);
    print(constraints.maxHeight);

    return const SizedBox();
  },
)


The child must choose a size that satisfies the constraints passed by the parent. Flutter Box Constraints Guide


19. Tight Constraints


A tight constraint effectively forces a widget to use a specific size because its minimum and maximum values are equal.


For example:


BoxConstraints.tight(
  const Size(300, 200),
)

This means:


minWidth = 300
maxWidth = 300
minHeight = 200
maxHeight = 200

20. Loose Constraints


Loose constraints allow a widget to choose a smaller size while still respecting a maximum size.


For example:


BoxConstraints(
  minWidth: 0,
  maxWidth: 500,
)

The widget can choose a width between 0 and 500 logical pixels, depending on the rest of the layout.


21. Unbounded Constraints


Sometimes a widget can receive an unbounded constraint in one direction. This means that the maximum size may be effectively infinite.


constraints.maxHeight == double.infinity

Unbounded constraints commonly appear in certain Row, Column, and scrollable layouts. They can cause errors when a child tries to expand infinitely.


For example, placing an Expanded widget inside a vertically scrolling ListView can produce constraint-related errors because the main-axis height may be unbounded.


Understanding constraints is therefore important when working with LayoutBuilder. Flutter Constraints Documentation


22. LayoutBuilder with ConstrainedBox


You can combine LayoutBuilder with ConstrainedBox to create controlled responsive layouts.


LayoutBuilder(
  builder: (context, constraints) {
    return ConstrainedBox(
      constraints: BoxConstraints(
        maxWidth: constraints.maxWidth > 700
            ? 700
            : constraints.maxWidth,
      ),
      child: const Text(
        "Responsive content with maximum width",
      ),
    );
  },
)

23. LayoutBuilder with Center


A common pattern is to center content while limiting its width on larger layouts.


LayoutBuilder(
  builder: (context, constraints) {
    final width = constraints.maxWidth > 700
        ? 700.0
        : constraints.maxWidth * 0.9;

    return Center(
      child: SizedBox(
        width: width,
        child: const Text(
          "Centered Responsive Content",
        ),
      ),
    );
  },
)


24. LayoutBuilder for Responsive Forms


class ResponsiveForm extends StatelessWidget {
  const ResponsiveForm({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth < 600) {
          return const Column(
            children: [
              TextField(
                decoration: InputDecoration(
                  labelText: "First Name",
                ),
              ),
              SizedBox(height: 16),
              TextField(
                decoration: InputDecoration(
                  labelText: "Last Name",
                ),
              ),
            ],
          );
        }

        return const Row(
          children: [
            Expanded(
              child: TextField(
                decoration: InputDecoration(
                  labelText: "First Name",
                ),
              ),
            ),
            SizedBox(width: 16),
            Expanded(
              child: TextField(
                decoration: InputDecoration(
                  labelText: "Last Name",
                ),
              ),
            ),
          ],
        );
      },
    );
  }
}


25. LayoutBuilder for Login Pages


Login pages often need a narrow form on desktop and a full-width form on mobile.


class ResponsiveLogin extends StatelessWidget {
  const ResponsiveLogin({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        final formWidth = constraints.maxWidth > 500
            ? 420.0
            : constraints.maxWidth * 0.9;

        return Center(
          child: SizedBox(
            width: formWidth,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: const [
                Text(
                  "Login",
                  style: TextStyle(
                    fontSize: 30,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                SizedBox(height: 24),
                TextField(
                  decoration: InputDecoration(
                    labelText: "Email",
                  ),
                ),
                SizedBox(height: 16),
                TextField(
                  obscureText: true,
                  decoration: InputDecoration(
                    labelText: "Password",
                  ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}


26. LayoutBuilder for Product Cards


class ProductCard extends StatelessWidget {
  const ProductCard({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        final compact = constraints.maxWidth < 280;

        if (compact) {
          return Card(
            child: Column(
              children: const [
                Icon(Icons.shopping_bag, size: 50),
                Text("Product"),
                Text("₹999"),
              ],
            ),
          );
        }

        return Card(
          child: Row(
            children: const [
              Padding(
                padding: EdgeInsets.all(16),
                child: Icon(
                  Icons.shopping_bag,
                  size: 70,
                ),
              ),
              Column(
                crossAxisAlignment:
                    CrossAxisAlignment.start,
                children: [
                  Text(
                    "Product",
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  Text("₹999"),
                ],
              ),
            ],
          ),
        );
      },
    );
  }
}


27. LayoutBuilder for Sidebar and Details


A common adaptive pattern is to show a sidebar and details panel side-by-side when enough horizontal space is available.


class AdaptivePage extends StatelessWidget {
  const AdaptivePage({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth > 600) {
          return Row(
            children: [
              const SizedBox(
                width: 280,
                child: Sidebar(),
              ),
              const VerticalDivider(width: 1),
              const Expanded(
                child: DetailsPanel(),
              ),
            ],
          );
        }

        return const Sidebar();
      },
    );
  }
}


Flutter's official adaptive-layout tutorial uses LayoutBuilder to switch between a compact navigation-based layout and a large layout containing a sidebar and details area. Flutter Adaptive Layout Tutorial


28. LayoutBuilder and Navigation


You can change navigation according to available width.


LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth < 600) {
      return const NavigationBar(
        destinations: [
          NavigationDestination(
            icon: Icon(Icons.home),
            label: "Home",
          ),
          NavigationDestination(
            icon: Icon(Icons.settings),
            label: "Settings",
          ),
        ],
      );
    }

    return const NavigationRail(
      selectedIndex: 0,
      destinations: [
        NavigationRailDestination(
          icon: Icon(Icons.home),
          label: Text("Home"),
        ),
        NavigationRailDestination(
          icon: Icon(Icons.settings),
          label: Text("Settings"),
        ),
      ],
    );
  },
)


The exact breakpoint should depend on whether the available space is sufficient for the selected navigation design. Flutter's adaptive guidance gives 600 logical pixels as an example threshold for switching between compact and larger navigation patterns. Flutter Adaptive Design Guidance


29. LayoutBuilder and Wrap


Wrap can automatically move children to another line when there is insufficient horizontal space.


LayoutBuilder(
  builder: (context, constraints) {
    return Wrap(
      spacing: 10,
      runSpacing: 10,
      children: const [
        Chip(label: Text("Flutter")),
        Chip(label: Text("Dart")),
        Chip(label: Text("Firebase")),
        Chip(label: Text("UI")),
        Chip(label: Text("Responsive")),
      ],
    );
  },
)

This is useful for tags, filters, buttons, categories, and other content whose width can vary.


30. LayoutBuilder with ListView


LayoutBuilder can be placed inside scrollable layouts to adapt a section according to the constraints it receives.


ListView(
  padding: const EdgeInsets.all(16),
  children: [
    LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth < 500) {
          return const Text("Compact content");
        }

        return const Text("Wide content");
      },
    ),
  ],
)


When using LayoutBuilder inside complex scrollable structures, pay attention to which axis is bounded and which axis may be unbounded.


31. LayoutBuilder Inside a Row


When LayoutBuilder is used inside a Row, the constraints it receives depend on how the Row allocates space to that child.


Row(
  children: [
    const SizedBox(
      width: 150,
      child: Text("Sidebar"),
    ),
    Expanded(
      child: LayoutBuilder(
        builder: (context, constraints) {
          return Text(
            "Content width: ${constraints.maxWidth}",
          );
        },
      ),
    ),
  ],
)

Here, the Expanded widget gives the LayoutBuilder the remaining horizontal space.


32. LayoutBuilder Inside a Column


Column(
  children: [
    const SizedBox(
      height: 100,
      child: Text("Header"),
    ),
    Expanded(
      child: LayoutBuilder(
        builder: (context, constraints) {
          return Center(
            child: Text(
              "Available height: ${constraints.maxHeight}",
            ),
          );
        },
      ),
    ),
  ],
)

The Expanded widget makes the LayoutBuilder receive the remaining available height.


33. LayoutBuilder and Expanded


Expanded and LayoutBuilder often work together when building responsive layouts.


Row(
  children: [
    Expanded(
      child: LayoutBuilder(
        builder: (context, constraints) {
          return Container(
            height: 200,
            color: Colors.blue,
            child: Center(
              child: Text(
                "Width: ${constraints.maxWidth}",
                style: const TextStyle(
                  color: Colors.white,
                ),
              ),
            ),
          );
        },
      ),
    ),
    const SizedBox(width: 16),
    Expanded(
      child: Container(
        height: 200,
        color: Colors.green,
      ),
    ),
  ],
)

34. LayoutBuilder and Flexible


Flexible can also provide a bounded area in which LayoutBuilder can determine available space.


Row(
  children: [
    Flexible(
      child: LayoutBuilder(
        builder: (context, constraints) {
          return Text(
            "Available: ${constraints.maxWidth}",
          );
        },
      ),
    ),
    const SizedBox(width: 20),
    const Text("Other Content"),
  ],
)

35. Reusable Responsive Widget


A reusable responsive widget can hide breakpoint logic from the rest of the application.


class ResponsiveBuilder extends StatelessWidget {
  final Widget mobile;
  final Widget desktop;

  const ResponsiveBuilder({
    super.key,
    required this.mobile,
    required this.desktop,
  });

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth < 600) {
          return mobile;
        }

        return desktop;
      },
    );
  }
}


Usage:


ResponsiveBuilder(
  mobile: const MobileHomePage(),
  desktop: const DesktopHomePage(),
)

36. ResponsiveBuilder with Three Layouts


class ResponsiveBuilder extends StatelessWidget {
  final Widget small;
  final Widget medium;
  final Widget large;

  const ResponsiveBuilder({
    super.key,
    required this.small,
    required this.medium,
    required this.large,
  });

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth < 600) {
          return small;
        }

        if (constraints.maxWidth < 1024) {
          return medium;
        }

        return large;
      },
    );
  }
}


37. Using LayoutBuilder with Builder Logic


Keep the builder callback focused on layout decisions.


LayoutBuilder(
  builder: (context, constraints) {
    final width = constraints.maxWidth;

    final isCompact = width < 600;
    final isMedium = width >= 600 && width < 1024;

    if (isCompact) {
      return const CompactLayout();
    }

    if (isMedium) {
      return const MediumLayout();
    }

    return const LargeLayout();
  },
)


38. LayoutBuilder and Adaptive Design


Responsive design generally means fitting the UI into the available space, while adaptive design also considers which layout is appropriate for that space.


LayoutBuilder is particularly useful for the measurement step because it provides the constraints at a specific point in the widget tree. Flutter's adaptive design guidance describes a three-step process: Abstract, Measure, and Branch. Flutter General Approach to Adaptive Apps


39. LayoutBuilder Build Timing


Unlike a normal Builder, LayoutBuilder's builder callback is invoked during layout and receives the constraints from the parent.


The callback can be called:



  • The first time the widget is laid out.

  • When the parent provides different constraints.

  • When the LayoutBuilder configuration changes.

  • When relevant dependencies used by the builder change.


Flutter's API documentation describes LayoutBuilder as a widget that defers building until layout so the builder can use the incoming constraints. LayoutBuilder API Documentation


40. LayoutBuilder vs Builder








BuilderLayoutBuilder
Provides BuildContext.Provides BuildContext and BoxConstraints.
Used for creating a new build context.Used for building according to layout constraints.
Does not provide parent size constraints.Provides parent layout constraints.
Useful for accessing context-dependent information.Useful for responsive and adaptive components.

41. LayoutBuilder vs Container


Container is primarily a layout and decoration widget. It does not automatically provide the parent's constraints to a builder callback.


LayoutBuilder specifically exposes those constraints:


LayoutBuilder(
  builder: (context, constraints) {
    return Container(
      width: constraints.maxWidth,
      height: 100,
    );
  },
)

42. LayoutBuilder vs MediaQuery Example


class ComparisonExample extends StatelessWidget {
  const ComparisonExample({super.key});

  @override
  Widget build(BuildContext context) {
    final windowWidth =
        MediaQuery.widthOf(context);

    return Container(
      width: 500,
      padding: const EdgeInsets.all(20),
      child: LayoutBuilder(
        builder: (context, constraints) {
          return Column(
            children: [
              Text(
                "Window Width: $windowWidth",
              ),
              Text(
                "Local Width: ${constraints.maxWidth}",
              ),
            ],
          );
        },
      ),
    );
  }
}


This example demonstrates the difference between the overall application-window width and the local width available to a particular widget.


43. Common Mistakes with LayoutBuilder


Mistake 1: Confusing Screen Size with Local Constraints


LayoutBuilder does not directly provide the entire screen size. It provides the constraints passed by its parent.


Mistake 2: Ignoring Unbounded Constraints


Do not assume that maxWidth and maxHeight will always be finite.


Mistake 3: Using Too Many Breakpoints


Use breakpoints only when the layout actually needs to change. Avoid creating unnecessary breakpoint conditions.


Mistake 4: Hardcoding Everything


LayoutBuilder should be combined with flexible widgets instead of replacing every dimension with manually calculated values.


Mistake 5: Using Device Type Instead of Available Space


Responsive decisions should generally be based on the available constraints rather than assumptions about whether the hardware is a phone, tablet, or desktop.


Mistake 6: Putting Complex Business Logic in the Builder


Use the builder primarily for layout decisions. Keep data processing and business logic in appropriate application layers.


44. Best Practices



  • Use LayoutBuilder when a widget needs to respond to its parent's available space.

  • Use constraints.maxWidth for width-based responsive decisions.

  • Use constraints.maxHeight when vertical space matters.

  • Use MediaQuery when the overall application-window size is what matters.

  • Use LayoutBuilder for reusable components that may be placed in different containers.

  • Keep breakpoint logic simple and meaningful.

  • Use Expanded and Flexible to distribute available space.

  • Use Wrap when items should move naturally to additional lines.

  • Use ConstrainedBox or maximum widths when content should not grow indefinitely.

  • Test components inside different parent sizes.

  • Check for unbounded constraints when working with rows, columns, and scrollables.

  • Do not assume a widget has the same width as the application window.


45. Complete Responsive LayoutBuilder Example


import 'package:flutter/material.dart';

class ResponsiveHome extends StatelessWidget {
  const ResponsiveHome({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Responsive Layout"),
      ),
      body: LayoutBuilder(
        builder: (context, constraints) {
          final width = constraints.maxWidth;

          if (width < 600) {
            return const MobileLayout();
          }

          if (width < 1000) {
            return const TabletLayout();
          }

          return const DesktopLayout();
        },
      ),
    );
  }
}

class MobileLayout extends StatelessWidget {
  const MobileLayout({super.key});

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: const [
        Card(
          child: ListTile(
            leading: Icon(Icons.home),
            title: Text("Home"),
          ),
        ),
        Card(
          child: ListTile(
            leading: Icon(Icons.person),
            title: Text("Profile"),
          ),
        ),
        Card(
          child: ListTile(
            leading: Icon(Icons.settings),
            title: Text("Settings"),
          ),
        ),
      ],
    );
  }
}

class TabletLayout extends StatelessWidget {
  const TabletLayout({super.key});

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      padding: const EdgeInsets.all(20),
      crossAxisCount: 2,
      crossAxisSpacing: 20,
      mainAxisSpacing: 20,
      children: const [
        Card(child: Center(child: Text("Home"))),
        Card(child: Center(child: Text("Profile"))),
        Card(child: Center(child: Text("Settings"))),
        Card(child: Center(child: Text("Reports"))),
      ],
    );
  }
}

class DesktopLayout extends StatelessWidget {
  const DesktopLayout({super.key});

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        const SizedBox(
          width: 250,
          child: ColoredBox(
            color: Colors.blueGrey,
            child: Center(
              child: Text(
                "Sidebar",
                style: TextStyle(
                  color: Colors.white,
                ),
              ),
            ),
          ),
        ),
        Expanded(
          child: GridView.count(
            padding: const EdgeInsets.all(30),
            crossAxisCount: 4,
            crossAxisSpacing: 20,
            mainAxisSpacing: 20,
            children: const [
              Card(child: Center(child: Text("Home"))),
              Card(child: Center(child: Text("Profile"))),
              Card(child: Center(child: Text("Settings"))),
              Card(child: Center(child: Text("Reports"))),
            ],
          ),
        ),
      ],
    );
  }
}


46. Practical Use Cases












Use CaseLayoutBuilder Usage
Responsive cardsChange card design based on available width.
DashboardsChange the number of columns.
FormsSwitch between vertical and horizontal fields.
NavigationSwitch between compact and wide navigation.
Product gridsChange the number of products per row.
SidebarsShow sidebar when sufficient horizontal space exists.
Reusable widgetsAdapt a component to different parent sizes.
Web layoutsRespond to browser resizing.

47. Practice Exercises



  1. Create a widget that displays its maxWidth and maxHeight.

  2. Create a responsive card that changes from Column to Row when its width reaches 400 pixels.

  3. Create a dashboard with 1 column below 600 pixels, 2 columns between 600 and 1000 pixels, and 4 columns above 1000 pixels.

  4. Create a responsive login form with a maximum width of 450 pixels.

  5. Create a product card that changes its design according to the available width.

  6. Create a sidebar that appears only when enough horizontal space is available.

  7. Create a reusable ResponsiveBuilder widget.

  8. Use LayoutBuilder inside an Expanded widget and display its available width.

  9. Build a responsive navigation interface using LayoutBuilder.

  10. Resize a Flutter web browser window and observe how the LayoutBuilder-based interface changes.


48. Quick Revision













ConceptExplanation
LayoutBuilderBuilds a widget according to constraints from its parent.
BoxConstraintsDescribes minimum and maximum width and height.
maxWidthMaximum horizontal space available.
maxHeightMaximum vertical space available.
minWidthMinimum horizontal space allowed.
minHeightMinimum vertical space allowed.
MediaQueryUseful for overall application-window information.
LayoutBuilder + ExpandedUseful for responsive layouts inside flexible areas.
LayoutBuilder + GridViewUseful for responsive grid columns.

49. Official Flutter Resources



50. Flutter Course Resources


For structured Flutter learning and practical training, explore these resources:



Conclusion


LayoutBuilder is a powerful Flutter widget for creating responsive and adaptive components. It provides a BoxConstraints object containing the minimum and maximum width and height available from the parent. This makes LayoutBuilder especially useful when a widget needs to adapt to its own local space rather than the size of the entire application window.


Use MediaQuery when you need information about the overall application window and use LayoutBuilder when a component needs to respond to the constraints provided by its parent. Combining LayoutBuilder with widgets such as Expanded, Flexible, Wrap, GridView, ConstrainedBox, and SafeArea allows you to create flexible interfaces that work across different screen sizes and layouts. Learn more about Flutter adaptive layouts


whatsapp